package crap;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.MemoryImageSource;
import java.io.IOException;
import java.util.ArrayList;

import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;

import tools.Arrow;
import tools.ColorConversions;
import tools.Derivative;
import tools.Gauss;

public class PickingTheRightPixels_commented {
	static int count = 2000;

	public static void main(String[] args) throws Exception {
		try {
			/*
			 * passende skalierungsstufe des features
			 */
			
			final BufferedImage kermit = ImageIO.read(Thread.currentThread().getContextClassLoader().getResourceAsStream("res/kermit001.jpg"));
			final int w = kermit.getWidth(), h = kermit.getHeight(), w2 = w / 2, h2 = h / 2;
			// int n = 16;

			final int[] pixels = kermit.getRGB(0, 0, w, h, new int[w * h], 0, w);
			int[] lum = ColorConversions.getFastLuminance(pixels, new int[pixels.length]);

			final MemoryImageSource mis = new MemoryImageSource(w, h, pixels,0, w);
			mis.setAnimated(true);
			
			/*
			 * berechnen der ableitungen in x und y richtung
			 */
			
			int[] dx = Derivative.dx(lum, w, h, new int[lum.length]);
			int[] dy = Derivative.dy(lum, w, h, new int[lum.length]);

			/*
			 * berechnen der betraege und winkel der ableitungen
			 */
			
			double[] lengths = Derivative.getLengths(dx, dy,
					new double[dx.length]);
			double[] angles = Derivative.getAngles(dx, dy,
					new double[dx.length]);

			
			/*
			 * rotation des deskriptors
			 */
			
			double theta = Math.toRadians(13);

			/*
			 * lage des deskriptors
			 */
			
			final AffineTransform at2 = AffineTransform.getTranslateInstance(0.25, 0.125);
			at2.preConcatenate(AffineTransform.getScaleInstance(2, 2));
			
			final AffineTransform at = new AffineTransform(); // zoom per mausrad -> siehe mousewheelistener
			
			at2.concatenate(AffineTransform.getRotateInstance(theta));

			final ArrayList<double[]> descriptor = new ArrayList<double[]>();
			final Rectangle2D selection = new Rectangle2D.Double();

			Point2D centerD = new Point2D.Double();
			centerD = at2.transform(centerD, centerD);
			final AffineTransform invers = at2.createInverse();

			final double maxDist = Math.sqrt(128);

			JFrame ff = new JFrame();
			ff.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			Point2D a = new Point2D.Double(100, 100), b = new Point2D.Double(
					500, 300);

			final int[] pixels2 = new int[w * h];
			Derivative.prepareLengths(lengths, pixels2);
			ColorConversions.buildRGB(pixels2, pixels2, pixels2, pixels);
			System.arraycopy(pixels, 0, pixels2, 0, w * h);

			mis.newPixels();
			kermit.setRGB(0, 0, w, h, pixels, 0, w);
			double arrowWidth = 10, arrowHeight = 40;

			final Arrow arrw = new Arrow();
			arrw.setArrow(a, b, arrowWidth, arrowHeight);
			final AffineTransform translator = AffineTransform.getTranslateInstance(w / 2, h / 2);

			final AffineTransform rotat0r = new AffineTransform();
			final Point2D centre = new Point2D.Double(100, 100);

			final JComponent canvas = new JComponent() {
				{
					setPreferredSize(new Dimension(w, h));
				}
				Line2D line = new Line2D.Double();
				Image im = createImage(mis);

				@Override
				public void paint(Graphics g) {
					Graphics2D g2 = (Graphics2D) g;

					g2.transform(at);

					g2.drawImage(im, 0, 0, this);

					g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
							RenderingHints.VALUE_ANTIALIAS_ON);
					g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
							RenderingHints.VALUE_STROKE_PURE);
					g2.setRenderingHint(RenderingHints.KEY_RENDERING,
							RenderingHints.VALUE_RENDER_QUALITY);
					g2.setStroke(new BasicStroke(0.1f));

					g2.setColor(Color.cyan);
					line.setLine(0, h / 2, w, h / 2);
					g2.draw(line);
					line.setLine(w / 2, 0, w / 2, h);
					g2.draw(line);

					g2.setColor(Color.magenta);
					for (int x = -2; x < 2; x++) {
						for (int y = -2; y < 2; y++) {
							selection.setFrame(x * 4, y * 4, 4, 4);
							Shape transSelection = at2
									.createTransformedShape(selection);
							Rectangle bounds = translator.createTransformedShape(transSelection).getBounds();

							g2.setColor(Color.green);
							g2.draw(bounds);
							Point2D p = new Point2D.Double();
							for (int j = (int) Math.floor(bounds.getMinY()), endy = (int) Math.ceil(bounds.getMaxY()); j < endy; j++) {
								for (int i = (int) Math.floor(bounds.getMinX()), endx = (int) Math.ceil(bounds.getMaxX()); i < endx; i++) {
//									System.out.println(i+" "+j);
									p.setLocation(i, j);
									try {
										p = translator.inverseTransform(p, p);
										p = at2.inverseTransform(p, p);
									} catch (NoninvertibleTransformException nte) {
										nte.printStackTrace();
									}
//									 System.out.println(p);

									if (selection.contains(p)) {
										pixels[i + j * w] = 0xFFFF0000;
									}
//									else {
//										pixels[i + j * w] = pixels2[i + j * w];
//									}
								}
							}
							mis.newPixels();
							Shape inversTransBounds = invers
									.createTransformedShape(bounds);
							bounds = inversTransBounds.getBounds();
							g2.setColor(Color.red);
							g2.draw(selection);
							g2.setColor(Color.yellow);
							g2.draw(translator.createTransformedShape(at2
									.createTransformedShape(selection)));
							// if (x==-2&&y==-2) {
							// g2.setColor(Color.yellow);
							// g2.draw(inversTransBounds);
							// g2.draw(translator.createTransformedShape(bounds));

							// }
						}
					}

					super.paint(g);
				}
			};
			canvas.addMouseWheelListener(new MouseWheelListener() {

				@Override
				public void mouseWheelMoved(MouseWheelEvent e) {

					double scale = Math.pow(1.01, e.getWheelRotation());

					try {
						Point2D p = new Point2D.Double(e.getX(), e.getY());
						at.inverseTransform(p, p);
						at.concatenate(AffineTransform.getTranslateInstance(
								p.getX(), p.getY()));
						at.concatenate(AffineTransform.getScaleInstance(scale,
								scale));
						at.concatenate(AffineTransform.getTranslateInstance(
								-p.getX(), -p.getY()));

					} catch (NoninvertibleTransformException nte) {
						nte.printStackTrace();
					}
					canvas.repaint();
				}
			});
			ff.add(canvas);
			// ff.setUndecorated(true);
			ff.pack();

			ff.setVisible(true);
		} catch (IOException iox) {
			iox.printStackTrace();
		}
	}
}
